[アップデート]S3からダウンストリームサービスに対してX-Rayのトレースコンテキストを伝搬できるようになりました
CX事業本部@大阪の岩田です。
11/16付けのアップデートにより、S3からダウンストリームサービスに対してX-Rayのトレースコンテキストを伝搬できるようになりました。
S3のイベント通知機能を利用すると、S3バケット上で発生したイベントを
- SNS
- SQS
- Lambda
といったサービスに対して伝搬することが可能ですが、今回のアップデートによりイベント伝搬時にS3側でX-Rayのトレースヘッダをよしなに処理してくれるようになりました。これによりアプリケーション全体を通したエンドツーエンドのトレースが実現できます。開発者は他のサービス利用時と同様にX-RayのSDKを利用するか、もしくは自前でHTTPリクエストヘッダX-Amzn-Trace-Id
を設定することでトレースが可能です。
注意点としては、S3がやってくれるのはあくまでトレースヘッダの伝搬だけです。特にイベント通知先が設定されていないバケットに対してPutObjectする際にX-Amzn-Trace-Id
を設定してもX-Rayにトレースデータは送信されません。トレースデータの送信はLambdaなどのダウンストリームサービス側で実施する必要があります。
やってみる
実際にLambda × S3の組み合わせでX-Rayのトレースを試してみます。今回は以下の環境で試しています
- Lambdaのランタイム:Python3.8
- X-Rayのトレースを有効化
- X-Ray SDK : 2.6.0
まずは下準備としてX-Ray SDKを内包するレイヤーを作成します。
$ pip install aws-xray-sdk -t python $ zip -r layer.zip python $ aws lambda publish-layer-version --zip-file fileb://layer.zip --layer-name xray-sdk --compatible-runtimes python3.8
以後利用するLambdaにはこのレイヤーを紐付けてX-Ray SDKを利用できるようにしています。
LambdaからPutObjectして、さらにLambaをトリガーしてみる
まずはシンプルにLambdaからS3にPutObjectしてみます。PutObject先のバケットはさらに別のLambdaをトリガーするよう事前に設定しておきます。 以下のコードでPutObjectを実行するLambda Functionを作成し、テストイベントを実行します。
import json import boto3 from aws_xray_sdk.core import patch_all patch_all() s3_client = boto3.client('s3') def lambda_handler(event, context): body = json.dumps({ 'key1': 'val1', 'key2': 'val2', 'key3': 'val3', }) s3_client.put_object(Bucket='<バケット名>', Key='<適当なオブジェクトキー>', Body=body) return { 'statusCode': 200, 'body': 'Hello from Lambda!' }
X-Rayのコンソールからトレース結果を確認してみます。
- PutObjectするLambda
- S3バケットのPutObjectからトリガーされるLambda
2つのLambdaを紐付けてしっかりトレースできていることが分かります。
Lambdaから発行したPresigned-URLに対してクライアントからPutObjectして、さらにLambaをトリガーしてみる
もう少し複雑なシナリオも試してみましょう。以下のような処理を想定しています。
- LambdaからPresigned-URLを発行
- 発行されたPresigned-URLを利用して、SPA等のクライアントからファイルアップロード処理(PutObject)を実行
- ファイルアップロード(PutObject)完了をトリガーに、さらに別のLambdaが起動して処理を行う
まずはPresigned-URL発行用のLambdaです
import json import os from botocore.client import Config import boto3 from aws_xray_sdk.core import patch_all patch_all() s3_client = boto3.client('s3', config=Config(signature_version='s3v4')) def lambda_handler(event, context): bucket = <適当なS3バケット> obj_key = <適当なオブジェクトキー> url = s3_client.generate_presigned_url(ClientMethod='put_object', Params={'Bucket': bucket, 'Key': obj_key}) return { 'url': url, 'xray-trace-id': os.getenv('_X_AMZN_TRACE_ID') }
このPresigned-URL発行用Lambdaを実行すると以下のようなレスポンスが返却されます。
{ "url": "https://<S3バケット名>.s3.amazonaws.com/<オブジェクトキー> "xray-trace-id": "Root=1-5fb4631d-2326f8eb1c1d621e0887f184;Parent=cb706fc48bc18be5;Sampled=1" }
レスポンスのxray-trace-id
にセットされたルートトレースIDを後続処理でも利用することで、エンドツーエンドのトレースが可能になります。
発行されたPresigned-URLに対してcurlコマンドでファイルアップロードを実行してみましょう。リクエストヘッダのX-Amzn-Trace-Id
には先程のPresigned-URL発行用Lambdaから出力されたトレースヘッダ(例: Root=1-5fb3ea8b-2931b7327d944b1e068cc275;Parent=57b80d29d09e35d7;Sampled=1
等)をそのまま設定して下さい。また、ファイルアップロード先のバケットはさらに別のLambdaをトリガーするよう事前に設定しておきます。
$curl "<発行されたPresigned-URL>" --upload-file <アップロードする適当なファイル> -H "X-Amzn-Trace-Id: <トレースヘッダ>"
ファイルアップロードが完了すると、後続のLambdaが自動起動しているはずです。少し待ってからX-Rayのトレース結果を確認してみます。
- Presigned-URL発行用Lambda
- S3のPutObjectをトリガーに起動するLambda
2つのLambdaを紐付けてエンドツーエンドでトレースできていることが分かります。Lambda間の空白の時間はざっくりとクライアント側でのアップロード所要時間と見なして良いでしょう。冒頭でも記載したとおり、S3側ではあくまでもトレースヘッダの伝搬しか行わないので、PutObjectの所要時間などを詳細にトレースしたい場合はクライアント側でX-Rayに対してトレースデータを送信してもらう必要があります。
まとめ
S3 × X-Rayの連携に関するアップデートを紹介しました。S3はAWSの鉄板サービスで、Lambdaから利用する機会も多いと思います。アプリケーションのトレーサビリティーを向上させるために、今回のアップデートを活用してX-Rayとの統合を検討してみてはいかがでしょうか?